#ifndef __MYSQL_CONTEXT_H__
#define __MYSQL_CONTEXT_H__
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "const.h"

class CTcpHandleBase;
class IPkg;
class IParser;
class BitMap;

typedef enum
{
	NIL = 0x00, //unknown
	C2M = 0x01, //client to mask
	M2M	= 0x02, //mask to mysql
}ConnType;

typedef enum
{
	CLOSED	 		= 0x00,
	REQ_CONNECT		= 0x01,
	RESP_HANDSHAKE	= 0x02,
	REQ_AUTH		= 0x03,
	RESP_AUTH		= 0x04,
	REQ_QUERY		= 0x05,
	RESP_QUERY		= 0x06,
	MAX_PROTO_NUM,
	//mysql_com.h->myStatusDesc
}Protocoll;

typedef enum
{
	OK			= 0x00, //
	ERR_IGNORE  = 0x01, //error request but ignore
	ERR_DROP	= 0x02, //error request do drop
	ERR_SWITCH	= 0x03, //error response, do switch
}Result;

typedef enum
{
	A_NIL = 0x00,
	A_OR = 0x01, //read only;
	A_OW = 0x02, //write only
	A_RW = 0x03, //read & write
}Access;

typedef enum
{
	M_NIL = 0x00,
	M_LOCK = 0x01,
	M_OUT  = 0x02,
}Mode;

typedef enum
{
	R_DEFAULT 	= 0x00,
	R_WHITE = 0x01,
	R_BLACK = 0x02,
}Rule;

typedef struct DB
{
	char ip[16];
	int port;
	Access access;
	Mode mode;
	DB()
	:port(0)
	,access(A_NIL)
	,mode(M_NIL)
	{
		memset(ip, 0x00, sizeof(ip));
	}

	DB& operator=(const DB& db)
	{
		sprintf(this->ip, "%s", db.ip);
		this->port = db.port;
		this->access = db.access;
		this->mode = db.mode;

		return *this;
	}
	bool operator==(const DB& db)
	{
		return (strcmp(this->ip, db.ip)==0 
			&& this->port==db.port);
			//&& this->access == db.access
			//&& this->mode == db.mode);
	}
};


#include <string>
#include <ext/hash_map>

using namespace std;
using namespace __gnu_cxx;

struct sql_hash{
	size_t operator()(const string& str) const
	{
		unsigned long __h = 0;
		for(size_t i = 0; i < str.size(); i++)
			__h = 5*__h + str[i];
		return size_t(__h);
	}
};

typedef hash_map<string, Rule, sql_hash> RuleTable;
typedef RuleTable::iterator RuleTableIter;
#define RTable RuleTable
#define RTIter RuleTableIter

typedef struct _config
{
	DB* 	dbList;
	int 	dbNum;
	int*	acl;
	int		aclNum;	
	Rule	rule;
	RTable* rTable;
	int		modifyTime;
}Config;

typedef struct _mysql
{
	Protocoll 	proto;
	const char* pBuff; //pkg buff ptr
	int			dwLen;
	IPkg*		pReqPkg;
	IPkg*		pRespPkg;
	int			dwLastReqSize;
	int			dwLastRespSize;
	IParser* 	pParser;  //sql parser handle
	IPkg*		pSelf;    //current pkg handle
	inline void Reset()
	{
		proto = CLOSED;
		pBuff = NULL;
		dwLen = 0;
		pReqPkg = NULL;
		pRespPkg = NULL;
		dwLastReqSize = 0;
		dwLastRespSize = 0;
		pParser = NULL;
		pSelf = NULL;
	}
}Mysql;

typedef struct _context
{
	bool	 useful;
	ConnType type;
	Mysql*	 pMysql;
	CTcpHandleBase* pBindHandler;
	DB*		pWorkDB;
	inline void Reset()
	{
		useful = false;
		type = NIL;
		if(pMysql != NULL)
		{
			pMysql->Reset();
			pMysql = NULL;
		}
		pBindHandler = NULL;
		pWorkDB = NULL;
	}
}Context;

typedef struct _bucket
{
	int iQueryNum;
	BitMap* pBitmap;
}Bucket;

typedef struct _ring_buckets
{
	int iRingSize;
	int	iTimeout;
	int	iKeepTime;
	Bucket*	pBucket;
}RingBuckets;

typedef enum _mysql_command
{
	MY_COM_SLEEP, 
   	MY_COM_QUIT,
   	MY_COM_INIT_DB,
   	MY_COM_QUERY, 
   	MY_COM_FIELD_LIST,
	MY_COM_CREATE_DB,
	MY_COM_DROP_DB,
	MY_COM_REFRESH, 
	MY_COM_SHUTDOWN,
	MY_COM_STATISTICS,
	MY_COM_PROCESS_INFO,
	MY_COM_CONNECT, 
	MY_COM_PROCESS_KILL,
	MY_COM_DEBUG, 
	MY_COM_PING,
	MY_COM_TIME,
	MY_COM_DELAYED_INSERT,
	MY_COM_CHANGE_USER,
	MY_COM_BINLOG_DUMP,
	MY_COM_TABLE_DUMP,
	MY_COM_CONNECT_OUT,
	MY_COM_REGISTER_SLAVE,
	MY_COM_STMT_PREPARE,
	MY_COM_STMT_EXECUTE,
	MY_COM_STMT_SEND_LONG_DATA,
	MY_COM_STMT_CLOSE,
	MY_COM_STMT_RESET,
	MY_COM_SET_OPTION, 
	MY_COM_STMT_FETCH,
	MY_COM_DAEMON,
 
  	/* Must be last */
	MY_COM_END
 }Command;

typedef struct _cmdInfo
{
	char* 	name;
	bool	isAccept;
}CmdInfo;

extern const CmdInfo pkgCmdInfo[];
extern const CmdInfo sqlCmdInfo[];
extern const char* retDesc[];
extern const int errorInfo[];


typedef struct memPiece
{
	memPiece()
	:pBuff(NULL)
	,iUse(0)
	,iHandle(0)
	{
	}
	~memPiece()
	{
		;
	}
	void Reset()
	{
		pBuff = NULL;
		iUse = 0;
		iHandle = 0;
	}
	void Set(char* pData, int iSize)
	{
		if(pBuff != NULL)
		{
			assert(pBuff+iUse == pData);
			iUse += iSize;
			return;
		}
		pBuff = pData;
		iUse = iSize;
			
		return;
	}
	char* pBuff;
	int   iUse;
	unsigned int	  iHandle;
}MemPiece;
#endif
